<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>treeOrList</title>
  </head>
  <body>
    <script>
      const listData = [
        {
          id: '01',
          name: '张大大',
          pid: null,
          job: '项目经理',
        },
        {
          id: '02',
          name: '小亮',
          pid: '01',
          job: '产品leader',
        },
        {
          id: '03',
          name: '小美',
          pid: '01',
          job: 'UIleader',
        },
        {
          id: '04',
          name: '老马',
          pid: '01',
          job: '技术leader',
        },
        {
          id: '05',
          name: '老王',
          pid: '01',
          job: '测试leader',
        },
        {
          id: '06',
          name: '老李',
          pid: '01',
          job: '运维leader',
        },
        {
          id: '07',
          name: '小丽',
          pid: '02',
          job: '产品经理',
        },
        {
          id: '08',
          name: '大光',
          pid: '02',
          job: '产品经理',
        },
        {
          id: '09',
          name: '小高',
          pid: '03',
          job: 'UI设计师',
        },
        {
          id: '10',
          name: '小刘',
          pid: '04',
          job: '前端工程师',
        },
        {
          id: '11',
          name: '小华',
          pid: '04',
          job: '后端工程师',
        },
        {
          id: '12',
          name: '小李',
          pid: '04',
          job: '后端工程师',
        },
        {
          id: '13',
          name: '小赵',
          pid: '05',
          job: '测试工程师',
        },
        {
          id: '14',
          name: '小强',
          pid: '05',
          job: '测试工程师',
        },
        {
          id: '15',
          name: '小涛',
          pid: '06',
          job: '运维工程师',
        },
      ];

      const treeData = [
        {
          id: '01',
          name: '张大大',
          pid: null,
          job: '项目经理',
          children: [
            {
              id: '02',
              name: '小亮',
              pid: '01',
              job: '产品leader',
              children: [
                {
                  id: '07',
                  name: '小丽',
                  pid: '02',
                  job: '产品经理',
                  children: [],
                },
                {
                  id: '08',
                  name: '大光',
                  pid: '02',
                  job: '产品经理',
                  children: [],
                },
              ],
            },
            {
              id: '03',
              name: '小美',
              pid: '01',
              job: 'UIleader',
              children: [
                {
                  id: '09',
                  name: '小高',
                  pid: '03',
                  job: 'UI设计师',
                  children: [],
                },
              ],
            },
            {
              id: '04',
              name: '老马',
              pid: '01',
              job: '技术leader',
              children: [
                {
                  id: '10',
                  name: '小刘',
                  pid: '04',
                  job: '前端工程师',
                  children: [],
                },
                {
                  id: '11',
                  name: '小华',
                  pid: '04',
                  job: '后端工程师',
                  children: [],
                },
                {
                  id: '12',
                  name: '小李',
                  pid: '04',
                  job: '后端工程师',
                  children: [],
                },
              ],
            },
            {
              id: '05',
              name: '老王',
              pid: '01',
              job: '测试leader',
              children: [
                {
                  id: '13',
                  name: '小赵',
                  pid: '05',
                  job: '测试工程师',
                  children: [],
                },
                {
                  id: '14',
                  name: '小强',
                  pid: '05',
                  job: '测试工程师',
                  children: [],
                },
              ],
            },
            {
              id: '06',
              name: '老李',
              pid: '01',
              job: '运维leader',
              children: [
                {
                  id: '15',
                  name: '小涛',
                  pid: '06',
                  job: '运维工程师',
                  children: [],
                },
              ],
            },
          ],
        },
      ];

      //1. ======「扁平数组」转「树形结构」======
      function treeing(arr) {
        const tree = [];
        const map = {};
        for (let item of arr) {
          // 一个新的带children的结构
          let newItem = (map[item.id] = {
            ...item,
            // children: [],
          });
          if (map[item.pid]) {
            // 父节点已存进map则在父节点的children添加新元素
            const parent = map[item.pid];
            if (!parent?.children) {
              parent.children = [];
            }
            parent.children.push(newItem);
            if (parent.children.length === 0) delete parent.children;
          } else {
            // 没有父节点，在根节点添加父节点
            tree.push(newItem);
          }
        }
        return tree;
      }

      const treeing2 = (arr, pid = null) => {
        const result = [];
        const getChildren = (arr, result, pid) => {
          for (const item of arr) {
            if (item.pid === pid) {
              const newItem = { ...item, children: [] };
              result.push(newItem);
              getChildren(arr, newItem.children, item.id);
            }
          }
        };
        getChildren(arr, result, pid);
        return result;
      };

      function treeing3(arr, pid = null) {
        let result = [];
        arr.forEach((item) => {
          if (item.pid === pid) result.push(item);
        });
        result.forEach((item) => {
          item.children = treeing3(arr, item.id);
          if (item.children.length === 0) delete item.children;
        });
        return result;
      }

      function treeing4(arr, pid = null) {
        const res = [];
        arr.forEach((item) => {
          if (item.pid === pid) {
            item.children = treeing4(arr, item.id);
            res.push(item);
          }
        });
        return res;
      }

      console.log('treeing(listData)', treeing(listData));
      console.log('treeing2(listData)', treeing2(listData));
      console.log('treeing3(listData)', treeing3(listData));
      console.log('treeing4(listData)', treeing4(listData));

      //2. ======「树形结构」转「扁平数组」======
      function flatten(tree, arr = []) {
        tree.forEach((item) => {
          const { children, ...props } = item;
          // 添加除了children的属性
          arr.push(props);
          if (children) {
            // 递归将所有节点加入到结果集中
            flatten(children, arr);
          }
        });
        return arr;
      }

      function flatten1(tree) {
        let arr = [];
        tree.forEach((item) => {
          const { children = [], ...props } = item;
          // 添加除了children的属性
          arr.push(props);
          if (children?.length) {
            // 递归将所有节点加入到结果集中
            arr.push(...flatten(children));
          }
        });
        return arr;
      }
      function flatten2(tree) {
        const list = [];
        const queue = [...tree];
        while (queue.length) {
          const node = queue.shift();
          const { children = [], ...item } = node;
          list.push(item);
          if (children?.length) {
            queue.push(...children);
          }
        }
        return list;
      }

      console.log('flatten(treeData)', flatten(treeData));
      console.log('flatten1(treeData)', flatten1(treeData));
      console.log('flatten2(treeData)', flatten2(treeData));

      // 3.======获取树形结构的最大层级======
      const getTreeMaxLevel = (arr) => {
        let maxLevel = 1;

        (function callBack(arr, level) {
          level++;
          maxLevel = Math.max(level, maxLevel);
          for (let i = 0; i < arr.length; i++) {
            const item = arr[i];
            if (item.children && item.children) {
              callBack(item.children, level);
            } else {
              continue;
            }
          }
        })(arr, 0);

        return maxLevel;
      };

      // 4..======
      const menus = [
        { id: '1', name: '首页', code: 'trade', pid: null },
        {
          id: '2',
          name: '交易管理',
          code: 'trade',
          pid: null,
          children: [
            {
              id: '3',
              name: '交易查询',
              code: 'trade-1',
              pid: '2',
              children: [{ id: '4', name: '交易查询-查询操作', code: 'trade-1-1', pid: '3' }],
            },
          ],
        },
        {
          id: '5',
          name: '权限管理',
          code: 'authorization',
          pid: null,
          children: [
            { id: '6', name: '角色管理', code: 'authorization-1', pid: '5' },
            { id: '7', name: '用户管理', code: 'authorization-2', pid: '5' },
          ],
        },
      ];
      // filterTree(menus, (item) => item.name.indexOf('管理') > -1);
      const gsdfass = [
        { id: '2', name: '交易管理', code: 'trade', pid: null, children: [] },
        {
          id: '5',
          name: '权限管理',
          code: 'authorization',
          pid: null,
          children: [
            { id: '6', name: '角色管理', code: 'authorization-1', pid: '5' },
            { id: '7', name: '用户管理', code: 'authorization-2', pid: '5' },
          ],
        },
      ];
    </script>
  </body>
</html>
